# 1.React Hook
Hook 分类
除了 useRef,其他都可以归类为 自变量/因变量
# 自变量
- useState
- useReducer
- useContext
# useState
// 1 定义x的方法,并且初始值为 0
const [x,setX] = useState(0);
// 3 定义改变x的方法,每次调用时 都会让x的只+1
const changeX = () => setX(x + 1);
// 2 接着定义组件所描述的字符,并将x的值 渲染为li 标签的值
// 4 将changex 绑定为ul的回调函数,点击视图触发更新; x 变化 => 视图变化
<ul onClick={changeX}>
<li>x是{x}</li>
</ul>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
描述一下函数组件.useState 定义了 x,x 的变化导致 li 的变化,所以 useState 是自变量,导致了 li 的变化=> 对应了视图变化;
# 组件的功能不仅描述视图,还能产生副作用 - useEffect
const [x, setX] = useState(0);
const changeX = () => setX(x + 1);
// 调用useEffect,依赖于x,当x 变化时,将title 赋值为x
useEffect(() => {
document.title = x;
}, [x]);
// 第一个参数是函数,异步操作。
// 第二个参数是数组,代表依赖项,依赖项变化则执行第一个函数。
// 数组可以省略,省略则在每一次组件渲染都会执行一次。
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 进阶: 从 useState 到 useReducer
- useReducer 解决的问题:假设有数据 a,要进行传递。只有一级层次的情况下可以通过 props 传递,但是如果有 n 级组件,那么一级传到 n 级会很麻烦。
- 如何解决:在一级组件通过 createContext 后,在后续组件需要用到地方通过 useContext 可以直接消费一级组件的 context。
# 因变量
- useMemo
- useEffect
- useCallback
# 可以缓存的 useMemo 和 useCallback
- 可以用 useMemo 和 useCallback 分别包裹 y 和 cahngeX
- useMemo 用来缓存一个因变量,需要显式的指定因变量依赖的自变量
- useCallback 缓存一个函数类型的因变量,也需要显式的指定依赖的自变量
const [x, setX] = useState(0);
const y = useMemo(() => 2 * x + 1, [x]); // 需要显式的指定y依赖于x的变化
// useCallback 缓存一个函数类型的因变量
const changX = useCallback(() => setX(x + 1), [x]);
1
2
3
4
5
2
3
4
5
- 可以看到使用 useMemo 和 useCallback 也是一样的;
- 使用 hooks 显式指明因变量
- 使用的时候 y 和 changeX 会被缓存下来,只要 x 不变,始终读取的是缓存的值
- 不使用的时候,每次函数组件调用,都会创建新的 y 和 changeX
- 在遇到性能瓶颈之前,都可以不使用这 2 个 hooks
# useMemo和useCallback的区别
- useMemo 经常与 useCallback 一同出现。当尝试优化子组件时,它们都很有用。他们会 记住(或者说,缓存)正在传递的东西:
import { useMemo, useCallback } from 'react';
function ProductPage({ productId, referrer }) {
const product = useData('/product/' + productId);
const requirements = useMemo(() => { //调用函数并缓存结果
return computeRequirements(product);
}, [product]);
const handleSubmit = useCallback((orderDetails) => { // 缓存函数本身
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]);
return (
<div className={theme}>
<ShippingForm requirements={requirements} onSubmit={handleSubmit} />
</div>
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
区别在于你需要缓存 什么:
useMemo 缓存函数调用的结果。在这里,它缓存了调用 computeRequirements(product) 的结果。除非 product 发生改变,否则它将不会发生变化。这让你向下传递 requirements 时而无需不必要地重新渲染 ShippingForm。必要时,React 将会调用传入的函数重新计算结果。
useCallback 缓存函数本身。不像 useMemo,它不会调用你传入的函数。相反,它缓存此函数。从而除非 productId 或 referrer 发生改变,handleSubmit 自己将不会发生改变。这让你向下传递 handleSubmit 函数而无需不必要地重新渲染 ShippingForm。直至用户提交表单,你的代码都将不会运行。
如果你已经熟悉了 useMemo,你可能发现将 useCallback 视为以下内容会很有帮助:
// 在 React 内部的简化实现
function useCallback(fn, dependencies) {
return useMemo(() => fn, dependencies);
}
1
2
3
4
2
3
4